package com.itchen.school.common.database;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.itchen.school.common.jdkext.Function1;
import com.itchen.school.common.jdkext.lambda.LambdaUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;

public class LambdaWrapper<T> {
    private QueryWrapper<T> _wrapper;

    private LambdaWrapper() {
    }

    public LambdaWrapper(QueryWrapper<T> wrapper) {
        this._wrapper = wrapper;
    }

    private String _an(String aliasName) {
        return StringUtils.isEmpty(aliasName) ? "" : aliasName + ".";
    }

    private String _cn(String fieldName) {
        return StringUtils.camelToUnderline(fieldName);
    }

    public <R> LambdaWrapper<T> eq(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.eq(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> ne(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.ne(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> lt(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.lt(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> le(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.le(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> gt(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.gt(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> ge(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.ge(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> in(String aliasName, Function1<R, ?> column, Object... values) {
        this._wrapper.in(this._an(aliasName) + LambdaUtils.getFieldName(column), values);
        return this;
    }

    public <R> LambdaWrapper<T> in(String aliasName, Function1<R, ?> column, Collection<?> values) {
        this._wrapper.in(this._an(aliasName) + LambdaUtils.getFieldName(column), values);
        return this;
    }

    public <R> LambdaWrapper<T> notIn(String aliasName, Function1<R, ?> column, Collection<?> values) {
        this._wrapper.notIn(this._an(aliasName) + LambdaUtils.getFieldName(column), values);
        return this;
    }

    public <R> LambdaWrapper<T> like(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.like(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> or() {
        this._wrapper.or();
        return this;
    }

    public <R> LambdaWrapper<T> likeLeft(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.likeLeft(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> likeRight(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.likeRight(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> notLike(String aliasName, Function1<R, ?> column, Object value) {
        this._wrapper.notLike(this._an(aliasName) + LambdaUtils.getFieldName(column), value);
        return this;
    }

    public <R> LambdaWrapper<T> isNull(String aliasName, Function1<R, ?> column) {
        QueryWrapper var10000 = this._wrapper;
        String var10001 = this._an(aliasName);
        var10000.isNull(var10001 + LambdaUtils.getFieldName(column));
        return this;
    }

    public <R> LambdaWrapper<T> isNotNull(String aliasName, Function1<R, ?> column) {
        QueryWrapper var10000 = this._wrapper;
        String var10001 = this._an(aliasName);
        var10000.isNotNull(var10001 + LambdaUtils.getFieldName(column));
        return this;
    }

    public <R> LambdaWrapper<T> groupBy(String aliasName, Function1<R, ?>... columns) {
        String asName = this._an(aliasName);
        Arrays.stream(columns).forEach((c) -> {
            this._wrapper.groupBy(asName + LambdaUtils.getFieldName(c));
        });
        return this;
    }

    @SafeVarargs
    public final <R> LambdaWrapper<T> orderByAsc(String aliasName, Function1<R, ?>... columns) {
        String asName = this._an(aliasName);
        Arrays.stream(columns).forEach((c) -> {
            this._wrapper.orderByAsc(asName + LambdaUtils.getFieldName(c));
        });
        return this;
    }

    @SafeVarargs
    public final <R> LambdaWrapper<T> orderByDesc(String aliasName, Function1<R, ?>... columns) {
        String asName = this._an(aliasName);
        Arrays.stream(columns).forEach((c) -> {
            this._wrapper.orderByDesc(asName + LambdaUtils.getFieldName(c));
        });
        return this;
    }

    @SafeVarargs
    public final <R> LambdaWrapper<T> orderBy(String aliasName, boolean isAsc, Function1<R, ?>... columns) {
        return isAsc ? this.orderByAsc(aliasName, columns) : this.orderByDesc(aliasName, columns);
    }

    public <R> LambdaWrapper<T> select(String aliasName, Function1<R, ?>... columns) {
        String anName = this._an(aliasName);
        Arrays.stream(columns).forEach((c) -> {
            this._wrapper.select(new String[]{anName + LambdaUtils.getFieldName(c)});
        });
        return this;
    }

    public <R> LambdaWrapper<T> selectColums(String aliasName, Function1<R, ?>... columns) {
        String anName = this._an(aliasName);
        ArrayList<String> list = new ArrayList();
        Arrays.stream(columns).forEach((c) -> {
            list.add(anName + LambdaUtils.getFieldName(c));
        });
        this._wrapper.select(new String[]{(String)list.stream().map(String::toString).collect(Collectors.joining(","))});
        return this;
    }

    public <R> LambdaWrapper<T> apply(String applySql) {
        this._wrapper.apply(applySql, new Object[0]);
        return this;
    }

    public QueryWrapper<T> ok() {
        return this._wrapper;
    }
}
